package com.shanzhu.volunteer.modules.volunteer.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.shanzhu.volunteer.common.entity.Response;
import com.shanzhu.volunteer.common.utils.EntityCopyUtil;
import com.shanzhu.volunteer.common.utils.SecurityUtil;
import com.shanzhu.volunteer.interfaces.body.volunteer.profession.ProfessionBody;
import com.shanzhu.volunteer.modules.volunteer.entity.enums.TagEnum;
import com.shanzhu.volunteer.modules.volunteer.entity.model.CeCollege;
import com.shanzhu.volunteer.modules.volunteer.entity.model.CeProfession;
import com.shanzhu.volunteer.modules.volunteer.entity.model.CeScoreLine;
import com.shanzhu.volunteer.modules.volunteer.entity.model.CeTagRel;
import com.shanzhu.volunteer.modules.volunteer.repository.ICeCollegeRepo;
import com.shanzhu.volunteer.modules.volunteer.repository.ICeProfessionRepo;
import com.shanzhu.volunteer.modules.volunteer.repository.ICeScoreLineRepo;
import com.shanzhu.volunteer.modules.volunteer.repository.ICeTagRelRepo;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 专业查询管理
 *
 * @author: ShanZhu
 * @date: 2023-04-01 20:55:09
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class CeProfessionService {

    private final ICeProfessionRepo professionRepo;

    private final ICeCollegeRepo collegeRepo;

    private final ICeScoreLineRepo scoreLineRepo;

    private final ICeTagRelRepo tagRelRepo;

    /**
     * 请求专业列表
     *
     * @param professionBody 专业请求体
     * @return 专业列表
     */
    public List<CeProfession> selectProfessionList(ProfessionBody professionBody) {
        List<CeProfession> ceProfessions = professionRepo.selectProfessionList(
                EntityCopyUtil.copyEntity(CeProfession.class, professionBody)
        );

        List<String> collegeNos = ceProfessions.stream()
                .filter(
                        profession -> StrUtil.isNotBlank(profession.getProfessionNo())
                ).map(CeProfession::getCollegeNo)
                .collect(Collectors.toList());

        //获取院校map
        Map<String, CeCollege> collegeMap = collegeRepo.selectCollegeListByNos(collegeNos)
                .stream().collect(Collectors.toMap(
                        CeCollege::getCollegeNo, Function.identity(), (v1, v2) -> v1
                ));

        //分数线map
        Map<String, List<CeScoreLine>> scoreLineMap = scoreLineRepo.selectScoreLineByCollegeNos(collegeNos)
                .stream().collect(Collectors.groupingBy(
                                scoreLine -> ofProfessionKey(scoreLine.getProfessionNo(), scoreLine.getCollegeNo())
                        )
                );

        //标签map
        Map<Integer, List<CeTagRel>> tagRelMap = tagRelRepo.selectTagsByTypeAndRelIds(
                TagEnum.PROFESSION,
                ceProfessions.stream().map(CeProfession::getId).collect(Collectors.toList())
        ).stream().collect(Collectors.groupingBy(
                CeTagRel::getRelId
        ));


        //组装专业对象vo列表
        generateProfessionVo(ceProfessions, collegeMap, scoreLineMap, tagRelMap);

        return ceProfessions;
    }

    /**
     * 添加专业
     *
     * @param professionBody 专业请求体
     * @return 结果
     */
    @Transactional
    public Response<Boolean> addProfession(ProfessionBody professionBody) {
        if (StrUtil.isNotBlank(professionBody.getCollegeNo())) {
            CeCollege college = collegeRepo.selectCollegeByNo(professionBody.getCollegeNo());
            if (college == null) {
                return new Response<>().failMsg("保存专业信息失败，院校代码 '" + professionBody.getProfessionNo() + "' 不存在");
            }
        }
        CeProfession ceProfession = EntityCopyUtil.copyEntity(CeProfession.class, professionBody);
        ceProfession.setCreatedUser(SecurityUtil.getUsername());

        //保存专业
        professionRepo.save(ceProfession);

        //保存分数线
        bindScoreLines(professionBody);

        return new Response<>(Boolean.TRUE);
    }

    /**
     * 编辑专业
     *
     * @param professionBody 专业请求体
     * @return 结果
     */
    @Transactional
    public Response<Boolean> editProfession(ProfessionBody professionBody) {
        if (StrUtil.isNotBlank(professionBody.getCollegeNo())) {
            CeCollege college = collegeRepo.selectCollegeByNo(professionBody.getCollegeNo());
            if (college == null) {
                return new Response<>().failMsg("编辑专业信息失败，院校代码 '" + professionBody.getProfessionNo() + "' 不存在");
            }
        }

        CeProfession ceProfession = EntityCopyUtil.copyEntity(CeProfession.class, professionBody);
        ceProfession.setUpdatedUser(SecurityUtil.getUsername());

        //编辑专业
        professionRepo.updateById(ceProfession);

        //保存分数线
        bindScoreLines(professionBody);

        return new Response<>(Boolean.TRUE);
    }

    /**
     * 通过专业id查询专业信息
     *
     * @param professionId 专业id
     * @return 结果
     */
    public CeProfession getProfession(Integer professionId) {
        CeProfession ceProfession = professionRepo.getById(professionId);
        //专业名称
        if (StrUtil.isNotBlank(ceProfession.getCollegeNo())) {
            CeCollege ceCollege = collegeRepo.selectCollegeByNo(ceProfession.getCollegeNo());
            if (ceCollege != null) {
                ceProfession.setCollegeName(ceCollege.getCollegeName());
            }
        }
        //分数线
        List<CeScoreLine> scoreLines = scoreLineRepo.selectScoreLineByKey(
                ceProfession.getCollegeNo(), ceProfession.getProfessionNo());
        ceProfession.setScoreLines(
                scoreLines.stream().map(scoreLine ->
                        new CeProfession.ScoreLineWrapper()
                                .setYear(scoreLine.getYear())
                                .setScore(scoreLine.getScore())
                ).collect(Collectors.toList())
        );

        return ceProfession;
    }

    /**
     * 删除专业
     *
     * @param professionIds 专业id列表
     * @return 结果
     */
    public Response<Boolean> deleteProfessionIds(Integer[] professionIds) {
        professionRepo.removeByIds(Arrays.asList(professionIds));
        return new Response<>(Boolean.TRUE);
    }

    /**
     * 保存分数线
     *
     * @param professionBody 请求对象
     */
    private void bindScoreLines(ProfessionBody professionBody) {
        //清空下记录
        scoreLineRepo.unBindScoreLines(professionBody.getProfessionNo(), professionBody.getCollegeNo());

        //保存分数线
        if (CollUtil.isNotEmpty(professionBody.getScoreLines())) {
            scoreLineRepo.saveBatch(
                    professionBody.getScoreLines().stream().map(
                            scoreLineWrapper -> {
                                CeScoreLine scoreLine = new CeScoreLine();
                                scoreLine.setProfessionNo(professionBody.getProfessionNo());
                                scoreLine.setCollegeNo(professionBody.getCollegeNo());
                                scoreLine.setYear(scoreLineWrapper.getYear());
                                scoreLine.setScore(scoreLineWrapper.getScore());
                                scoreLine.setCreatedUser(SecurityUtil.getUsername());
                                return scoreLine;
                            }
                    ).collect(Collectors.toSet())
            );
        }
    }

    /**
     * professionNo + '#' + collegeNo 生成专业唯一key
     *
     * @param professionNo 专业代码
     * @param collegeNo    院校代码
     * @return 唯一key
     */
    private static String ofProfessionKey(String professionNo, String collegeNo) {
        return professionNo + "#" + collegeNo;
    }

    /**
     * 组装专业对象vo列表
     *
     * @param ceProfessions 专业对象
     * @param collegeMap    院校map
     * @param scoreLineMap  分数线map
     * @param tagMap        标签map
     */
    private static void generateProfessionVo(
            List<CeProfession> ceProfessions,
            Map<String, CeCollege> collegeMap,
            Map<String, List<CeScoreLine>> scoreLineMap,
            Map<Integer, List<CeTagRel>> tagMap
    ) {
        ceProfessions.forEach(
                profession -> {
                    //把专业名称填充进去
                    profession.setCollegeName(
                            collegeMap.getOrDefault(
                                    profession.getCollegeNo(), new CeCollege()
                            ).getCollegeName()
                    );
                    //把分数线填充进去
                    profession.populateScoreLineText(
                            scoreLineMap.get(ofProfessionKey(profession.getProfessionNo(), profession.getCollegeNo()))
                    );
                    //把标签填充进去
                    profession.generateTagNameText(tagMap.get(profession.getId()));
                    //修改录取率为其加上%符号
                    profession.setAcceptanceRate(
                            profession.getAcceptanceRate() + "%"
                    );
                });
    }
}

  